from typing import Union
import wave
import pyaudio
import uvicorn
from fastapi import FastAPI, Form
from pydantic import BaseModel
import base64
import urllib
import requests
import json
import os
from langchain_community.utilities import SQLDatabase
from langchain_openai import ChatOpenAI
from langchain_experimental.sql import SQLDatabaseChain
from fastapi.middleware.cors import CORSMiddleware

# 后端实例生成
app = FastAPI()

# 配置允许跨域请求的来源列表
origins = [
    "http://localhost",          # 本地开发环境
    "http://localhost:8080",     # 常见的前端开发服务器端口
    "http://localhost:5173",     # 例如Vue、React的开发服务器
    "https://your-production-domain.com"  # 生产环境域名
]

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,       # 允许的来源
    allow_credentials=True,      # 允许携带凭证（如cookies）
    allow_methods=["*"],         # 允许的HTTP方法（如GET、POST等）
    allow_headers=["*"],         # 允许的HTTP头
)

# 百度语音接口API配置
API_KEY = "uhSBGXU3NiyrHYaWKshDmIqZ"
SECRET_KEY = "LluQY4UZljIZghoPT8RNunFjhHqmcgqE"

# 音频录制参数配置
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
RECORD_SECONDS = 6



# 实例化大模型
llm = ChatOpenAI(
    base_url="https://api.deepseek.com/v1",  # DeepSeek API端点
    model="deepseek-reasoner",                  # DeepSeek模型标识
    # model="deepseek-chat", # 普通模型
    openai_api_key="sk-72c548e2ff234f66af740f685b3895fb",     # 替换为DeepSeek密钥
    max_tokens=100000,
    temperature=0.2
)



def get_file_size(file_path):
    """
    获取语音文件的字节数
    """
    try:
        return os.path.getsize(file_path)
    except FileNotFoundError:
        print("错误: 文件未找到!")
    except Exception as e:
        print(f"错误: 发生了一个未知错误: {e}")
    return None

def get_file_content_as_base64(path, urlencoded=False):
    """
    获取文件base64编码
    :param path: 文件路径
    :param urlencoded: 是否对结果进行urlencoded 
    :return: base64编码信息
    """
    with open(path, "rb") as f:
        content = base64.b64encode(f.read()).decode("utf8")
        if urlencoded:
            content = urllib.parse.quote_plus(content)
    return content

def get_access_token():
    """
    使用 AK，SK 生成鉴权签名（Access Token）
    :return: access_token，或是None(如果错误)
    """
    url = "https://aip.baidubce.com/oauth/2.0/token"
    params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
    return str(requests.post(url, params=params).json().get("access_token"))


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}

@app.get("/record_audio/")
async def record_audio():
    output_filename = 'test.wav'
    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)

    print("* 开始录制")

    frames = []

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK)
        frames.append(data)

    print("* 录制结束")

    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(output_filename, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

    return {"msg": f"音频已录制并保存为 {output_filename}"}

@app.get("/speech2word/")
def speech2word():
    url = "https://vop.baidu.com/server_api"
    speech_file_name = "test.wav"
    speech_file = get_file_content_as_base64(speech_file_name, False)
    # speech为录音文件
    payload = json.dumps({
        "format": "wav",
        "rate": RATE,
        "channel": CHANNELS,
        "cuid": "dCcIeCKDI6M4dF7n6iAlOYNXtUKiakMm",
        "speech": speech_file,
        "len": get_file_size(speech_file_name),
        "token": get_access_token()
    }, ensure_ascii=False)
    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }
    
    response = requests.request("POST", url, headers=headers, data=payload.encode("utf-8"))
    
    # 获取响应的 JSON 数据
    if response.status_code == 200:
        try:
            data = json.loads(response.text)
            print(data)
        except json.JSONDecodeError as e:
            print(f"解析 JSON 数据时出错: {e}")

    return data


@app.get("/getquestion/")
async def getquestion():
    output_filename = 'test.wav'
    p = pyaudio.PyAudio()

    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)

    print("* 开始录制")

    frames = []

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        data = stream.read(CHUNK)
        frames.append(data)

    print("* 录制结束")

    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(output_filename, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

    url = "https://vop.baidu.com/server_api"
    speech_file_name = output_filename
    speech_file = get_file_content_as_base64(speech_file_name, False)
    # speech为录音文件
    payload = json.dumps({
        "format": "wav",
        "rate": RATE,
        "channel": CHANNELS,
        "cuid": "dCcIeCKDI6M4dF7n6iAlOYNXtUKiakMm",
        "speech": speech_file,
        "len": get_file_size(speech_file_name),
        "token": get_access_token()
    }, ensure_ascii=False)
    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }
    
    print('* 开始识别')
    response = requests.request("POST", url, headers=headers, data=payload.encode("utf-8"))
    
    # 获取响应的 JSON 数据
    if response.status_code == 200:
        try:
            data = json.loads(response.text)
            print(data)
        except json.JSONDecodeError as e:
            print(f"解析 JSON 数据时出错: {e}")

    return data

# 获取 JSON 数据
class Question(BaseModel):
    question: str


@app.post("/deepseek2sale/")
def deepseek2sale(question: Question):
    # 建立数据库连接
    db = SQLDatabase.from_uri("sqlite:///car_sales.db")
    # 创建数据链
    db_chain = SQLDatabaseChain(llm=llm, database=db)
    # 执行问题
    result = db_chain.run(question.question)
    print(result)
    return result

@app.post("/deepseek2company/")
def deepseek2company(question: Question):
    print(f'前端提问：{question.question}')
    # 建立数据库连接
    db = SQLDatabase.from_uri("sqlite:///company_database.db")
    # 创建数据链
    # db_chain = SQLDatabaseChain(llm=llm, database=db)
    db_chain = SQLDatabaseChain.from_llm(llm, db)
    # 执行问题
    result = db_chain.run(question.question)
    print(result)
    return result

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
    


